package ruru.client.ui.widgets;

import java.util.List;

import ruru.client.RuruDkp;
import ruru.client.backend.RuruUtility;
import ruru.client.backend.rpcWrapper.StandingsDataRow;
import ruru.client.backend.rpcWrapper.StandingsDataWrapper;
import ruru.client.services.DataService;
import ruru.client.services.DataServiceAsync;
import ruru.client.ui.widgets.sortableTable.ComparableHTML;
import ruru.client.ui.widgets.sortableTable.ComparableLabel;
import ruru.client.ui.widgets.sortableTable.LastRaidDate;
import ruru.client.ui.widgets.sortableTable.Sortable;
import ruru.client.ui.widgets.sortableTable.SortableTable;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
import com.google.gwt.user.client.ui.HTMLTable.ColumnFormatter;
import com.google.gwt.user.client.ui.HTMLTable.RowFormatter;

public class StandingsWidget extends Composite {
	// A sortable table that includes standings information
	private SortableTable table;

	// Main widget's panel that includes both the standings table and the "last
	// updated" label
	private VerticalPanel panel;

	// Label that tells when the standings table was last updated
	private Label updated;
	private boolean initialized = false;
	Label loadingLabel = new Label("Loading...");

	public StandingsWidget() {
		panel = new VerticalPanel();
		table = new SortableTable();
		updated = new Label();

		panel.add(updated);
		panel.add(loadingLabel);
		loadingLabel.addStyleName("raid-loading-label");
		panel.add(table);
		panel.addStyleName("standings-container");
		panel.setSpacing(0);
		updated.addStyleName("standings-lastUpdated");
		table.setWidth("100%");

		initWidget(panel);
	}
	
	public void initialize() {
		if(!initialized) {
			getLastModifiedRaidTime();
			getStandingsData();
		}
		initialized = true;
	}

	public void setLastUpdated(long date) {
		updated.setText("Updated " + RuruUtility.lastUpdate(date) + " ago");

	}

	/**
	 * Gets the timestamp when the raid data was last modified
	 */
	public void getLastModifiedRaidTime() {
		DataServiceAsync ds = (DataServiceAsync) GWT.create(DataService.class);
		ServiceDefTarget endpoint = (ServiceDefTarget) ds;
		String moduleRelativeURL = GWT.getModuleBaseURL() + "/DataService";
		endpoint.setServiceEntryPoint(moduleRelativeURL);
		AsyncCallback callback = new AsyncCallback() {

			/**/
			public void onSuccess(Object result) {
				Long time = (Long) result;
				setLastUpdated(time.longValue());
				System.out.println("last updated raid time loaded in client: "
						+ (System.currentTimeMillis() - RuruDkp.start) + "ms");
			}
			/**/

			public void onFailure(Throwable caught) {
				System.out.println("in client: getLastModifiedRaidTime failure");
				caught.printStackTrace();
			}
		};
		ds.getLastModifiedRaidTime(callback);
	}

	public void getStandingsData() {
		DataServiceAsync ds = (DataServiceAsync) GWT.create(DataService.class);

		ServiceDefTarget endpoint = (ServiceDefTarget) ds;
		String moduleRelativeURL = GWT.getModuleBaseURL() + "/DataService";
		endpoint.setServiceEntryPoint(moduleRelativeURL);

		AsyncCallback callback = new AsyncCallback() {
			public void onSuccess(Object result) {
				processStandings((StandingsDataWrapper) result);
				panel.remove(loadingLabel);
				System.out.println("standings loaded in client: " + (System.currentTimeMillis() - RuruDkp.start) + "ms");
			}

			public void onFailure(Throwable caught) {
				System.out.println("in client: getRules failure");
				caught.printStackTrace();
			}
		};

		ds.getStandingsData(callback);
	}

	/**
	 * Loads each raider's name, class, maxbid, items recieved and latest raid data into the standings table
	 * 
	 * @param raiders
	 */
	private void processStandings(StandingsDataWrapper sdw) {
		table.addColumnHeader("Class", 0);
		table.addColumnHeader("Name", 1);
		table.addColumnHeader("DKP", 2);
		table.addColumnHeader("Liquidity", 3);
		table.addColumnHeader("Last Raid", 4);

		int activeRaiders = 0;
		int count = 0;
		List entries = sdw.getEntryList();
		for(int i = 0; i < entries.size(); i++) {
			final StandingsDataRow sdr = (StandingsDataRow) entries.get(i);
			if(!sdr.getRetired()) {
				activeRaiders++;

				table.setValue(count + 1, 0, sdr.getColorClassHTML());
				ComparableLabel name = new ComparableLabel(sdr.getName());
				name.addStyleName("activate-link");
				name.addClickListener(new ClickListener() {
					public void onClick(Widget sender) {
						RuruDkp.switchToPersonalDkpPage(RuruUtility.lowerFirstLetter(sdr.getName()), sdr.getRaidClass(), sdr.getName());
					}					
				});
				table.setValue(count + 1, 1, name);

				ComparableHTML d = new ComparableHTML(RuruUtility.twoDecimals(sdr.getDkp()));
				table.setValue(count + 1, 2, d);
				table.setValue(count + 1, 3, new ComparableHTML(RuruUtility.twoDecimals(sdr.getLiquidity())));

				/**
				 * calls getLastRaidDate on all raiders, meaning if not all the raid data has been loaded (raiders not
				 * having "last raid date" set), this throws exceptions!
				 * 
				 * TODO: fixed exception throwing in a messy way: gives an empty string when raid date hasn't been loaded
				 * for a raider. See LastRaidDate.java's toString method and Raider.java's getLastRaidDate method.
				 */
				// table.setValue(count + 1, 4, new LastRaidDate(sdr.getLastRaidDate()));
				table.setValue(count + 1, 4, new LastRaidDate(sdr.getLastRaidDate()));
				// i++;
				count++;
			}
		}

		CellFormatter cellFormatter = table.getCellFormatter();
		for(int k = 0; k < count + 1; k++) {
			for(int j = 0; j < 5; j++) {
				cellFormatter = table.getCellFormatter();
				cellFormatter.addStyleName(k, j, "sortable-table-cell");

				switch(j) {
				case 0:
					cellFormatter.addStyleName(k, j, "text-align-center");
				case 1:
					cellFormatter.addStyleName(k, j, "text-align-center");
					break;
				case 2:
					cellFormatter.addStyleName(k, j, "text-align-right");
				case 3:
					cellFormatter.addStyleName(k, j, "text-align-right");
				case 4:
					cellFormatter.addStyleName(k, j, "text-align-right");
				default:
					break;
				}
			}
		}

		ColumnFormatter colForm = table.getColumnFormatter();
		colForm.setWidth(0, "10%");
		// colForm.setWidth(1, "25%");
		colForm.setWidth(2, "12%");
		colForm.setWidth(3, "15%");
		// colForm.setWidth(4, "auto");

		colForm.addStyleName(0, "text-align-center");
		colForm.addStyleName(1, "text-align-center");
		colForm.addStyleName(2, "text-align-right");
		colForm.addStyleName(3, "text-align-right");
		colForm.addStyleName(4, "text-align-right");

		table.addStyleName("sortable-table");
		table.setCellSpacing(0);

		// Set Style Name for the header
		RowFormatter rowFormatter = table.getRowFormatter();
		rowFormatter.addStyleName(0, "standings-tableHeader");

		for(int rowIndex = activeRaiders; rowIndex > 0; rowIndex--) {
			rowFormatter.addStyleName(rowIndex, "row");
		}

		table.forceSort(0, Sortable.SORT_ASC);
		panel.addStyleName("standings-widget-left-padding-hack");
	}
}